package Tools;

public class SmartCode {
	private static String[] charTable={
		"AA", //	0
		"AB", //	1
		"AC", //	2
		"AD", //	3
		"AE", //	4
		"AF", //	5
		"AG", //	6
		"AH", //	7
		"AI", //	8
		"AJ", //	9
		"AK", //	10
		"AL", //	11
		"AM", //	12
		"AN", //	13
		"AO", //	14
		"AP", //	15
		"AQ", //	16
		"AR", //	17
		"AS", //	18
		"AT", //	19
		"AU", //	20
		"AV", //	21
		"AW", //	22
		"AX", //	23
		"AY", //	24
		"AZ", //	25
		"BA", //	26
		"BB", //	27
		"BC", //	28
		"BD", //	29
		"BE", //	30
		"BF", //	31
		"BG", //	32
		"BH", //	33
		"BI", //	34
		"BJ", //	35
		"BK", //	36
		"BL", //	37
		"BM", //	38
		"BN", //	39
		"BO", //	40
		"BP", //	41
		"BQ", //	42
		"BR", //	43
		"BS", //	44
		"BT", //	45
		"BU", //	46
		"BV", //	47
		"BW", //	48
		"BX", //	49
		"BY", //	50
		"BZ", //	51
		"CA", //	52
		"CB", //	53
		"CC", //	54
		"CD", //	55
		"CE", //	56
		"CF", //	57
		"CG", //	58
		"CH", //	59
		"CI", //	60
		"CJ", //	61
		"CK", //	62
		"CL", //	63
		"CM", //	64
		"CN", //	65
		"CO", //	66
		"CP", //	67
		"CQ", //	68
		"CR", //	69
		"CS", //	70
		"CT", //	71
		"CU", //	72
		"CV", //	73
		"CW", //	74
		"CX", //	75
		"CY", //	76
		"CZ", //	77
		"DA", //	78
		"DB", //	79
		"DC", //	80
		"DD", //	81
		"DE", //	82
		"DF", //	83
		"DG", //	84
		"DH", //	85
		"DI", //	86
		"DJ", //	87
		"DK", //	88
		"DL", //	89
		"DM", //	90
		"DN", //	91
		"DO", //	92
		"DP", //	93
		"DQ", //	94
		"DR", //	95
		"DS", //	96
		"DT", //	97
		"DU", //	98
		"DV", //	99
		"DW", //	100
		"DX", //	101
		"DY", //	102
		"DZ", //	103
		"EA", //	104
		"EB", //	105
		"EC", //	106
		"ED", //	107
		"EE", //	108
		"EF", //	109
		"EG", //	110
		"EH", //	111
		"EI", //	112
		"EJ", //	113
		"EK", //	114
		"EL", //	115
		"EM", //	116
		"EN", //	117
		"EO", //	118
		"EP", //	119
		"EQ", //	120
		"ER", //	121
		"ES", //	122
		"ET", //	123
		"EU", //	124
		"EV", //	125
		"EW", //	126
		"EX", //	127
		"EY", //	128
		"EZ", //	129
		"FA", //	130
		"FB", //	131
		"FC", //	132
		"FD", //	133
		"FE", //	134
		"FF", //	135
		"FG", //	136
		"FH", //	137
		"FI", //	138
		"FJ", //	139
		"FK", //	140
		"FL", //	141
		"FM", //	142
		"FN", //	143
		"FO", //	144
		"FP", //	145
		"FQ", //	146
		"FR", //	147
		"FS", //	148
		"FT", //	149
		"FU", //	150
		"FV", //	151
		"FW", //	152
		"FX", //	153
		"FY", //	154
		"FZ", //	155
		"GA", //	156
		"GB", //	157
		"GC", //	158
		"GD", //	159
		"GE", //	160
		"GF", //	161
		"GG", //	162
		"GH", //	163
		"GI", //	164
		"GJ", //	165
		"GK", //	166
		"GL", //	167
		"GM", //	168
		"GN", //	169
		"GO", //	170
		"GP", //	171
		"GQ", //	172
		"GR", //	173
		"GS", //	174
		"GT", //	175
		"GU", //	176
		"GV", //	177
		"GW", //	178
		"GX", //	179
		"GY", //	180
		"GZ", //	181
		"HA", //	182
		"HB", //	183
		"HC", //	184
		"HD", //	185
		"HE", //	186
		"HF", //	187
		"HG", //	188
		"HH", //	189
		"HI", //	190
		"HJ", //	191
		"HK", //	192
		"HL", //	193
		"HM", //	194
		"HN", //	195
		"HO", //	196
		"HP", //	197
		"HQ", //	198
		"HR", //	199
		"HS", //	200
		"HT", //	201
		"HU", //	202
		"HV", //	203
		"HW", //	204
		"HX", //	205
		"HY", //	206
		"HZ", //	207
		"IA", //	208
		"IB", //	209
		"IC", //	210
		"ID", //	211
		"IE", //	212
		"IF", //	213
		"IG", //	214
		"IH", //	215
		"II", //	216
		"IJ", //	217
		"IK", //	218
		"IL", //	219
		"IM", //	220
		"IN", //	221
		"IO", //	222
		"IP", //	223
		"IQ", //	224
		"IR", //	225
		"IS", //	226
		"IT", //	227
		"IU", //	228
		"IV", //	229
		"IW", //	230
		"IX", //	231
		"IY", //	232
		"IZ", //	233
		"JA", //	234
		"JB", //	235
		"JC", //	236
		"JD", //	237
		"JE", //	238
		"JF", //	239
		"JG", //	240
		"JH", //	241
		"JI", //	242
		"JJ", //	243
		"JK", //	244
		"JL", //	245
		"JM", //	246
		"JN", //	247
		"JO", //	248
		"JP", //	249
		"JQ", //	250
		"JR", //	251
		"JS", //	252
		"JT", //	253
		"JU", //	254
		"JV"  //	255
	};
	
	public static String encode(byte value){
		return charTable[value-Byte.MIN_VALUE];
	}

	public static byte decode(String value) throws Exception{
		for(int i=0;i<charTable.length; i++){
			if(charTable[i].equals(value)){
				return (byte) (i+Byte.MIN_VALUE);
			}
		}
		throw new Exception(String.format("String \"%s\" not found", value));
	}
	
	public static byte[] decodeBytes(String value) throws Exception{
		return decodeBytes(value, false);
	}
	public static byte[] decodeBytes(String value,boolean checksum) throws Exception{
		value=value.replace("-", "");
		if(value.length()%2==1){
			throw new Exception(String.format("String must have even Characters", value));
		}
		byte[] result = new byte[value.length()/2];
		for(int i=0;i<value.length(); i+=2){
			String chunk = value.substring(i, i+2);
			result[i/2]=decode(value.substring(i, i+2));
		}
		if (checksum){
			byte[] resultNoChecksum= new byte[result.length-2];
			for (int i=0;i<resultNoChecksum.length;i++){
				resultNoChecksum[i]=result[i];
			}
			result=null;
			result=resultNoChecksum;
		}
		
		return result;
	}
	public static String decodeString(String value) throws Exception{
		return decodeString(value,false);
	}
	
	public static String decodeString(String value,boolean checksum) throws Exception{
		
		byte[] mac=decodeBytes(value,checksum);
		try {
		} catch (Exception e2) {
			// TODO Auto-generated catch block
			e2.printStackTrace();
		}
		String code = "";
	        for (int i = 0; i < mac.length; i++) {
	        	code+=String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : "");
	        }
		return code;
	}
	
	
	public static boolean checksum(String value) throws Exception{
		return checksum(decodeBytes(value));
	}
	
	public static boolean checksum(byte[] value) throws Exception{
		if (value.length<2){
			throw new Exception("Checksum failed - length must be 4 bytes or higher");
		}
		if(value.length%2==1){
			throw new Exception(String.format("Checksum failed - code must have even bytes"));
		}
		
		byte checksumPari=0;
		for(int i=0; i<value.length-2; i+=2){
			checksumPari+=value[i];
			System.out.println(checksumPari+" ->"+value[i] );
		}
		byte checksumDispari=0;
		for(int i=1; i<value.length-2; i+=2){
			checksumDispari+=value[i];
		}
		if (checksumPari!=value[value.length-2]) return false;
		if (checksumDispari!=value[value.length-1]) return false;
		
		return true;
	}
	
	
	public static String encode(byte[] value){
		return encode(value,false);
	}

	public static String encode(byte[] value,boolean checksum){
		String str="";
		for(int i=0; i<value.length; i++){
			str+=encode(value[i]);
		}
		if (checksum) {
			byte checksumPari=0;
			for(int i=0; i<value.length; i+=2){
				checksumPari+=value[i];
			}
			byte checksumDispari=0;
			for(int i=1; i<value.length; i+=2){
				checksumDispari+=value[i];
			}
			str+=encode(checksumPari)+encode(checksumDispari);
		}
		for(int j=4;j<str.length();j+=5){
			str=new StringBuilder(str).insert(j, "-").toString();
		}
		
		return str;
	}
	
}
